package com.himaci.gtbattle.model;

import com.himaci.framework.utility.NumberUtils;

/**
 * Kelas skill
 *
 * @author XNPSDN
 */
public class Skill {

    // list id skill
    public static final int CRITICAL_ATTACK = 1;
    public static final int FOCUS_FIRE = 2;
    public static final int MANA_BURN = 3;
    public static final int CURSE = 4;
    public static final int SILENCE = 5;
    public static final int METEOR = 6;
    public static final int INCREASE_DEFENSE = 7;
    public static final int HEAL = 8;
    public static final int INCREASE_POWER = 9;
    // list skill
    public static final Skill CRITICAL_ATTACK_SKILL = new Skill(CRITICAL_ATTACK);
    public static final Skill FOCUS_FIRE_SKILL = new Skill(FOCUS_FIRE);
    public static final Skill MANA_BURN_SKILL = new Skill(MANA_BURN);
    public static final Skill CURSE_SKILL = new Skill(CURSE);
    public static final Skill SILENCE_SKILL = new Skill(SILENCE);
    public static final Skill METEOR_SKILL = new Skill(METEOR);
    public static final Skill INCREASE_DEFENSE_SKILL = new Skill(INCREASE_DEFENSE);
    public static final Skill HEAL_SKILL = new Skill(HEAL);
    public static final Skill INCREASE_POWER_SKILL = new Skill(INCREASE_POWER);
    // atribut
    public int id;
    public int manaCost;
    public String skillName;
    public String skillDesc;

    /**
     * Konstruktor
     * @param id Id yang menunjukkan nomor skill
     */
    public Skill(int id) {
	this.id = id;
	switch (id) {
	    case CRITICAL_ATTACK:
		manaCost = 20;
		skillName = "Critical Attack";
		skillDesc = "50% kemungkinan menyerang dgn kekuatan 3x ATK";
		break;
	    case FOCUS_FIRE:
		manaCost = 30;
		skillName = "Focus Fire";
		skillDesc = "Menyerang dengan kekuatan 2x ATK";
		break;
	    case MANA_BURN:
		manaCost = 15;
		skillName = "Mana Burn";
		skillDesc = "Membakar mana target dengan 50% kekuatan ATK";
		break;
	    case CURSE:
		manaCost = 30;
		skillName = "Curse";
		skillDesc = "Membuat seluruh tim lawan kehilangan 50% ATK, 1 turn";
		break;
	    case SILENCE:
		manaCost = 30;
		skillName = "Silence";
		skillDesc = "Membuat lawan tidak dapat menggunakan skill, 1 turn";
		break;
	    case METEOR:
		manaCost = 45;
		skillName = "Meteor";
		skillDesc = "Menyerang seluruh tim lawan dengan 50% ATK";
		break;
	    case INCREASE_DEFENSE:
		manaCost = 30;
		skillName = "Increase Defense";
		skillDesc = "Menambah 5 poin DEF seluruh tim, permanen";
		break;
	    case HEAL:
		manaCost = 30;
		skillName = "Heal";
		skillDesc = "Menambah HP target sesuai kekuatan ATK";
		break;
	    case INCREASE_POWER:
		manaCost = 45;
		skillName = "Increase Power";
		skillDesc = "Menambah 10 poin ATK seluruh tim, permanen";
		break;
	    default:
		manaCost = 0;
		break;
	}
    }

    /**
     * Mendapat skill yang sesuai dengan karakter dan aksi
     * @return Skill yang dimaksud
     */
    public static Skill getSkill(int charId, int actId) {
	switch (charId) {
	    case 0:
		switch (actId) {
		    case 0:
			return CRITICAL_ATTACK_SKILL;
		    case 1:
			return FOCUS_FIRE_SKILL;
		    case 2:
			return MANA_BURN_SKILL;
		}
	    case 1:
		switch (actId) {
		    case 0:
			return CURSE_SKILL;
		    case 1:
			return SILENCE_SKILL;
		    case 2:
			return METEOR_SKILL;
		}
	    case 2:
		switch (actId) {
		    case 0:
			return INCREASE_DEFENSE_SKILL;
		    case 1:
			return HEAL_SKILL;
		    case 2:
			return INCREASE_POWER_SKILL;
		}
	}
	return null;
    }

    /**
     * Apakah skill perlu menetapkan target
     * @return Perlu atau tidak
     */
    public boolean needTargetting() {
	if (id == CURSE || id == METEOR || id == INCREASE_DEFENSE || id == INCREASE_POWER) {
	    return false;
	}
	return true;
    }

    /**
     * Apakah dapat mengeksekusi skill atau tidak
     * @param executor Eksekutor
     * @param target Target
     * @return Bisa atau tidak
     */
    public boolean canExecute(GameChar executor, GameChar target) {
	if (executor.isDead()
		|| (target.isDead() && needTargetting())
		|| executor.isSilenced()
		|| executor.currEnergy < manaCost) {
	    return false;
	}
	return true;
    }

    /**
     * Eksekusi skill
     * @param executor Eksekutor
     * @param target Target
     */
    public void execute(GameChar executor, GameChar target) {
	if (canExecute(executor, target)) {
	    switch (id) {
		case CRITICAL_ATTACK:
		    exec1(executor, target);
		    break;
		case FOCUS_FIRE:
		    exec2(executor, target);
		    break;
		case MANA_BURN:
		    exec3(executor, target);
		    break;
		case CURSE:
		    exec4(executor, target);
		    break;
		case SILENCE:
		    exec5(executor, target);
		    break;
		case METEOR:
		    exec6(executor, target);
		    break;
		case INCREASE_DEFENSE:
		    exec7(executor, target);
		    break;
		case HEAL:
		    exec8(executor, target);
		    break;
		case INCREASE_POWER:
		    exec9(executor, target);
		    break;
		default:
		    return;
	    }
	    executor.currEnergy -= manaCost;
	}
    }

    /**
     * Eksekusi skill sesuai nomor (critical attack)
     * @param target Target serangan
     */
    private void exec1(GameChar executor, GameChar target) {
	if (NumberUtils.getInstance().generateRandomInt(10) < 5) {
	    executor.attack(target, 3);
	} else {
	    executor.attack(target);
	}

	target.state = GameChar.STATE_ATTACKED;
	target.stateTime = 0;
    }

    /**
     * Eksekusi skill sesuai nomor (focus fire)
     * @param target Target serangan
     */
    private void exec2(GameChar executor, GameChar target) {	
	executor.attack(target, 2);

	target.state = GameChar.STATE_ATTACKED;
	target.stateTime = 0;
    }

    /**
     * Eksekusi skill sesuai nomor (mana burn)
     * @param target Target serangan
     */
    private void exec3(GameChar executor, GameChar target) {
	target.currEnergy -= executor.getAttack() / 2;
	if (target.currEnergy < 0) {
	    target.currEnergy = 0;
	}

	target.state = GameChar.STATE_ATTACKED;
	target.stateTime = 0;
    }

    /**
     * Eksekusi skill sesuai nomor (curse)
     * @param target Target serangan
     */
    private void exec4(GameChar executor, GameChar target) {
	for (int i = 0; i < 3; ++i) {
	    if (!target.owner.characters[i].isDead()) {
		target.owner.characters[i].curse();
	    }
	}
    }

    /**
     * Eksekusi skill sesuai nomor (silent)
     * @param target Target serangan
     */
    private void exec5(GameChar executor, GameChar target) {
	target.silence();
    }

    /**
     * Eksekusi skill sesuai nomor (meteor)
     * @param target Target serangan
     */
    private void exec6(GameChar executor, GameChar target) {
	for (int i = 0; i < 3; ++i) {
	    if (!target.owner.characters[i].isDead()) {
		executor.attack(target.owner.characters[i], 0.5f);
		target.owner.characters[i].state = GameChar.STATE_ATTACKED;
		target.owner.characters[i].stateTime = 0;
	    }
	}
    }

    /**
     * Eksekusi skill sesuai nomor (inc def)
     * @param target Target serangan
     */
    private void exec7(GameChar executor, GameChar target) {
	int incDefAmmount = 5;
	int maxDefAmmount = 70;
	for (int i = 0; i < 3; ++i) {
	    if (!executor.owner.characters[i].isDead()) {
		executor.owner.characters[i].currDefense += incDefAmmount;
		if (executor.owner.characters[i].currDefense > maxDefAmmount) {
		    executor.owner.characters[i].currDefense = maxDefAmmount;
		}
		executor.owner.characters[i].state = GameChar.STATE_SUPPORTED;
		executor.owner.characters[i].stateTime = 0;
	    }
	}
    }

    /**
     * Eksekusi skill sesuai nomor (heal)
     * @param target Target serangan
     */
    private void exec8(GameChar executor, GameChar target) {
	if (target.isDead()) {
	    return;
	}
	target.currVitality += executor.getAttack();
	if (target.currVitality > target.maxVitality) {
	    target.currVitality = target.maxVitality;
	}

	target.state = GameChar.STATE_SUPPORTED;
	target.stateTime = 0;
    }

    /**
     * Eksekusi skill sesuai nomor (inc pow)
     * @param target Target serangan
     */
    private void exec9(GameChar executor, GameChar target) {
	int incAtkAmmount = 10;
	int maxAtkAmmount = 9999;
	for (int i = 0; i < 3; ++i) {
	    if (!executor.owner.characters[i].isDead()) {
		executor.owner.characters[i].currAttack += incAtkAmmount;
		if (executor.owner.characters[i].currAttack > maxAtkAmmount) {
		    executor.owner.characters[i].currAttack = maxAtkAmmount;
		}
		executor.owner.characters[i].state = GameChar.STATE_SUPPORTED;
		executor.owner.characters[i].stateTime = 0;
	    }
	}
    }
}
